<html xmlns="http://www.w3.org/1999/xhtml" xmlns:devlive="http://dev.live.com"> 
    <head>
        <title>Showing your contacts on a map</title>

	<!-- needed for Windows Live Contacts gadget -->
    <script type="text/javascript" src="http://controls.services.live.com/scripts/base/v0.3/live.js"></script>
    <script type="text/javascript" src="http://controls.services.live.com/scripts/base/v0.3/controls.js"></script>    
	
	<!-- needed for Virtual Earth -->
	<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>

        <style type="text/css">
            .earth {
                z-index:        1;
                width:          100%;
                height:         100%;
            }

            .message {
                filter:         alpha(opacity=80);
                opacity:        .8;
                z-index:        3;
                width:          15em;
                height:         15em;
                border:         solid 1px black;
                background:     white;
                visibility:     hidden;
                overflow:       auto;
                font-family:    Verdana;
                font-size:      75%;        
                position:       absolute;
            }
            
            #contactscontrol {
                z-index:        3;
                width:          12em;
                height:         18em;
                border:         solid 1px black;
                background:     white;
                position:       absolute;
            }

            /* push pin common style */
            .pushpinCommon {
            	position:absolute;
            	top:-20px; /*offset to get the pin accurate */
            	left:8px;
            	display:block;
            	width:30px; /* all pushpins are the same size */
            	height:36px;
            }            

            .contactPushpin {
            	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image, src='images/contact.png');
                background: url(images/contact.png) no-repeat;
            }

            /* browser does NOT support png alpha natively (IE6) */
            .browserNoAlpha {
            	visibility:visible;
            	background:none;
            }

            /* browser supports png alpha natively (Firefox & IE7) */
            .browserAlpha {
            	visibility:visible;
                filter:none;
            }


            #header {
                filter:         alpha(opacity=80);
                opacity:        .8;
                z-index:        2;
                font-family:    Verdana;
                font-size:      125%;        
                height:         4em;
                width:          100%;
                background:     white;
                border-bottom:  solid 1px #0088E4;
                position:       absolute;
                vertical-align: bottom
            }
        </style>

        <script type="text/javascript" language="javascript">
            //
            // contactMapper class
            //
            // The constructor accepts the ID of a map on which to place pushpins, 
            // and the ID of a DIV tag where messages are shown.
            // There is only one public method, namely plot(arrayOfUserData).
            // 
            // This geocoding technique can fail if a valid FindLocation call on
            // the geocoding map takes more than 5 seconds, since the Timeout may
            // start mapping your next contact while the onchangeview event on
            // the geocoding map returns for the previous contact (the location and
            // your contact can get out of sync). Microsoft is aware of the issue
            // and working on a solution.
            // 
            function contactMapper(mapToPushpinId, notificationDivID) {

                // class method definition
                this.plot = plot;

                // instantiate the map the user is seeing
                var m_map = new VEMap(mapToPushpinId);
                m_map.LoadMap();
                this.map = m_map;
                
                // instantiate hidden geocoding map
                var elMapGeocode = document.createElement("div");
                elMapGeocode.id = mapToPushpinId + '_geocode';
                elMapGeocode.style.position = 'absolute';
                elMapGeocode.style.left = '-1024px';
                elMapGeocode.style.top = '-768px';
                elMapGeocode.style.height = '100px';
                elMapGeocode.style.width = '100px';
                document.getElementById(mapToPushpinId).appendChild(elMapGeocode);
                var m_mapGeocode = new VEMap(elMapGeocode.id);
                m_mapGeocode.LoadMap();
                
                // function which plots users, and it's helper plotOneContact
                function plot(arrayOfUserData) {
                    m_map.DeleteAllPushpins();
                    document.getElementById(notificationDivID).style.visibility = "hidden";
                    document.getElementById(notificationDivID).innerHTML = "<P><H4>Contacts not mapped</H4></P>";
                    plotOneContact(0, arrayOfUserData);
                }
                
                function plotOneContact(index, arrayOfUserData) {
                    var name, email, personalstreet, personalcity, personalstate, personalcountry, personalpostalcode;
                    if (index < arrayOfUserData.length) {
                        name = (typeof arrayOfUserData[index].name != "undefined" ? arrayOfUserData[index].name : "");
                        email = (typeof arrayOfUserData[index].email != "undefined" ? arrayOfUserData[index].email : "");
                        personalstreet = (typeof arrayOfUserData[index].personalStreet != "undefined" ? arrayOfUserData[index].personalStreet : "");
                        personalcity = (typeof arrayOfUserData[index].personalCity != "undefined" ? arrayOfUserData[index].personalCity : "");
                        personalstate = (typeof arrayOfUserData[index].personalState != "undefined" ? arrayOfUserData[index].personalState : "");
                        personalcountry = (typeof arrayOfUserData[index].personalCountry != "undefined" ? arrayOfUserData[index].personalCountry : "");
                        personalpostalcode = (typeof arrayOfUserData[index].personalPostalCode != "undefined" ? arrayOfUserData[index].personalPostalCode : "");    
                        
                        if (
                            personalstreet == "" &&
                            personalcity == "" &&
                            personalstate == "" &&
                            personalcountry == "" &&
                            personalpostalcode == ""
                            ) {
                            document.getElementById(notificationDivID).innerHTML += 
                                "<P><a href='mailto:" +
                                encodeURIComponent(email) +
                                "?subject=Location in Windows Live Contacts" +
                                "&body=Your location information is missing.'>" +
                                hesc(name) + 
                                "</a></P>";
                            document.getElementById(notificationDivID).style.visibility = "visible";
                            plotOneContact(index + 1, arrayOfUserData);
                        } else {
                            timeoutId = window.setTimeout(
                                getStatefulRestartLoopCallback(index, arrayOfUserData, name),
                                5000);
                            m_mapGeocode.AttachEvent(
                                'onchangeview', 
                                getStatefulPushpinCallback(index, arrayOfUserData, timeoutId, name, email));
                            m_mapGeocode.FindLocation(
                                personalstreet + " " + 
                                personalcity + " " + 
                                personalstate + " " + 
                                personalcountry + " " + 
                                personalpostalcode);
                        }
                    } else {
                        window.status = "Complete.";
                    }
                }

                function getStatefulPushpinCallback(index, arrayOfUserData, timeoutId, name, email) {
                    return arrayOfUserData[index].callback = function() {
                        window.clearTimeout(timeoutId);
                        m_mapGeocode.DetachEvent('onchangeview', arrayOfUserData[index].callback);
                        var latlong = m_mapGeocode.GetCenter();
                        var title = "<P>" + hesc(name) + "</P>";
                        var description =
                            (email != "" ? 
                                "<nobr>" +
                                "Messenger " +
                                "<a href='msnim:chat?contact=" + hesc(email) + "'>Chat</a> " +
                                "<a href='msnim:voice?contact=" + hesc(email) + "'>Voice</a> " +
                                "<a href='msnim:video?contact=" + hesc(email) + "'>Video</a>" +
                                "</nobr>"
                                :
                                "");
                        var pin = new VEPushpin(
                            index + name, 
                            latlong,
                            "images/tdot.gif",
                            title,
                            description,
                            "pushpinCommon"+" "+"contactPushpin"+" "+alphaClass);
                        m_map.AddPushpin(pin);
                        plotOneContact(index + 1, arrayOfUserData);                   
                    }
                }

                // this callback function gets called by the timeout if finding the address requires more than 5 seconds.
                function getStatefulRestartLoopCallback(index, arrayOfUserData, name) {
                    return function() {
                        m_mapGeocode.DetachEvent('onchangeview', arrayOfUserData[index].callback);
                        document.getElementById(notificationDivID).innerHTML += 
                            "<P>Failed to map contact " +
                            hesc(name) + 
                            "</P>";
                        document.getElementById(notificationDivID).style.visibility = "visible";
                        plotOneContact(index + 1, arrayOfUserData);
                    }
                }
                
                // escape utilities
                function hesc(p_str) {
                    return p_str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
                }
            }

            //
            // global
            //
            var _cm;         // contactmapper instance
            var alphaClass;  //for pushpin alpha compatability
            
            //
            // page initializaiton
            //
            function docLoad()
            {
                try {
                    updateContactLayout();

                    _cm = new contactMapper('myMap', 'myMessage'); 
                    //_cm.map.AddControl(document.getElementById('ContactsControl')); 
                    _cm.map.AddControl(document.getElementById('header'));           
                    _cm.map.AddControl(document.getElementById('myMessage'));           

                    window.onresize = winResize;
                    winResize();

                    //"alpha-tize" all of the png images (i.e. so 24bit PNG alpha layer works with IE6)
                    alphaClass = (browserSupportsAlphaNatively()?"browserAlpha":"browserNoAlpha"); //for push pins

                } catch(e) {
                    var myMessage = document.getElementById('myMessage');
                    myMessage.innerHTML = "<P><H4>Unknown error</H4></P><P>Initialization of map and contacts failed.</P>";
                    myMessage.style.visibility = "visible";
                }
            }

            //
            // contact control event handler
            //           
            function signIn() {
                window.status  = "Logged in.";
            }

            function signOut() {
                window.status  = "Logged out.";
            }

            function error() {
                window.status  = "Data transfer error.";
            }

            function receiveData(p_contacts) {
                window.status  = "Received data.";
                _cm.plot(p_contacts);
            }

            //
            // layout utilities
            //           
            function winResize() {
                var dsbTop = document.getElementById('header').offsetHeight + 10;
                var dsb = document.getElementById("myMap_dashboard");
                dsb.style.top = dsbTop + "px";
                dsb.style.left = "10px";

                var el = document.getElementById("myMessage");
                var elTop = dsbTop + dsb.offsetHeight + 10;
                el.style.top = elTop + "px";
                el.style.left = "10px";
                updateContactLayout();
            }

            function updateContactLayout() {
                var el = document.getElementById("ContactsControl");
                el.style.top = (document.getElementById('header').offsetHeight + 10) + "px";
                el.style.left = (getWindowWidth() - 10 - el.offsetWidth) + "px";
            }

            function getWindowWidth(){
                if(window.innerWidth) return window.innerWidth;
                if(document.documentElement && document.documentElement.clientWidth)return document.documentElement.clientWidth;
                if(document.body && document.body.clientWidth)return document.body.clientWidth;
                return 0;
            }

            function browserSupportsAlphaNatively() {
                if (document.body.style.filter === undefined) {
                    return true; //dosn't support IE's CSS "filter" so assume native support for png alpha
                } else {
                    //if IE7 use native support not filter (although both will work)
                    var re = /MSIE (\d*)\.(\d*)/;
                    var vs = re.exec(window.navigator.appVersion);
                    return (parseInt(vs[1]) >= 7); //if major browser verion if < IE7
                }
            }

        </script>
    </head>
    <body onload="docLoad();" style="overflow:hidden">

        <div id="header">
            <h2>Showing your contacts on a map <font color='#FF3300'>Beta</font></h2>
        </div>

        <devlive:contactscontrol 
              id="ContactsControl"
              devlive:privacyStatementURL="http://g.msn.com/0PR_/enus"
              devlive:dataDesired="name,email,personalstreet,personalcity,personalstate,personalcountry,personalpostalcode"
              devlive:onData="receiveData"
              devlive:onSignin="signIn"
              devlive:onSignout="signOut"
              devlive:onError="error"
              devlive:channelEndpointURL="channel.htm" />

        <div id= "myMessage" class = "message">
        </div>

        <div id = "myMap" class = "earth">
        </div>
    </body>
</html>